// // ******************************************************************
// //       /\ /|       @file       Program.cs
// //       \ V/        @brief      await29
// //       | "")       @author     Await, 285283010@qq.com
// //       /  |
// //      /  \\        @Modified   2025-03-01 12:03
// //    *(__\_\        @Copyright  Copyright (c) , 2025-02-23 10:02 Await
// // ******************************************************************

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using AutomaticSubtitles.Service.BackgroundServices;
using AutomaticSubtitles.Service.DataAccess.MappProfile;
using AutomaticSubtitles.Service.Infrastructure.Helper;
using AutomaticSubtitles.Service.Infrastructure.JsonConverter;
using AutomaticSubtitles.Service.Infrastructure.Localization;
using AutomaticSubtitles.Service.Infrastructure.Middlewares;
using Masa.BuildingBlocks.Data;
using Microsoft.AspNetCore.ResponseCompression;
using OpenAI;
using Scalar.AspNetCore;
using Serilog;
using Serilog.Events;
using Xabe.FFmpeg;
using Xabe.FFmpeg.Downloader;
using System.Runtime.InteropServices;
using System.Reflection;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.OpenApi.Models;
using AutomaticSubtitles.Service.Domain.Filter;
using AutomaticSubtitles.Service.Infrastructure.Repositories;

System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton(new AppSettingHelper(builder.Configuration));

var sqlType = Environment.GetEnvironmentVariable("SQLTYPE") ?? SqlTypeString;
//TODO：ssss
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Error)
    .MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Error)
    .MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.StaticFiles", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Http", LogEventLevel.Warning)
    .ReadFrom.Configuration(builder.Configuration) // 从配置文件中读取Serilog配置
    .CreateLogger();
builder.Host.UseSerilog(); // 将Serilog配置到Host中

MappConfigure.Configure();

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
    options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.Never;
    // options.SerializerOptions.WriteIndented = true;
    options.SerializerOptions.IncludeFields = true;
    options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    options.SerializerOptions.Converters.Add(new DateTimeConverter());
    options.SerializerOptions.Converters.Add(new DoubleConverter());
    // options.SerializerOptions.Converters.Add(new StringConverter());
    options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
    options.SerializerOptions.Converters.Add(new DateTimeNullableConvert());
});
builder.Services.AddScoped<ExceptionMiddleware>(); //请求异常拦截中间件
// builder.Services.AddSingleton<IFilterWordsRepository, FilterWordsRepository>(); // 注册词语过滤仓储
builder.Services.AddMemoryCache();
builder.Services.AddHttpContextAccessor();
// builder.Services.AddOpenApi();
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<GzipCompressionProvider>();
    options.Providers.Add<BrotliCompressionProvider>();
    //只压缩这个类型的，图文不压缩
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "text/html", "application/json" });
});
GlobalConfigurationUtils.DefaultDesEncryptKey = Environment.GetEnvironmentVariable("DEFAULTDESENCRYPTKEY") ?? DefaultDesEncryptKey;
var corsPolicy = CorsPolicy;

// builder.Services.Configure<ConnectionStrings>(connectionString => { connectionString.DefaultConnection = "{Replace-Your-ConnectionString}"; });
var app = builder.Services
    .AddEndpointsApiExplorer()
    .AddLocalization(options => options.ResourcesPath = "Resources")
    .AddAuthorization()
    .AddMapster()
    .AddHttpClient()
    .AddHttpContextAccessor()
    .AddAutoMapper(typeof(Program))
    .AddJwtBearerAuthentication()
    .AddSingleton(_ =>
    {
        var localizationManager = new LocalizationManager();
        localizationManager.LoadAll().Wait();
        return localizationManager;
    })
    .AddSingleton(_ => //创建一个 Redis 客户端实例
    {
        var client = new RedisClient(RedisConnection)
        {
            Serialize = o => JsonSerializer.Serialize(o),
            Deserialize = (s, t) => JsonSerializer.Deserialize(s, t)
        };
        return client;
    })
    .AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1",
            new OpenApiInfo
            { Title = "AutomaticSubtitlesApp", Version = "v1", Contact = new OpenApiContact { Name = "AutomaticSubtitlesApp" } });
        foreach (var item in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.xml")) options.IncludeXmlComments(item, true);
        options.DocInclusionPredicate((docName, action) => true);
        JwtHelper.AddSwaggerAddJwtHeader(options);
    })
    .AddMasaDbContext<AutoDbContext>(opt => //数据库上下文
    {
        // opt.UseLoggerFactory(null);  // 禁用日志工厂
        // opt.EnableSensitiveDataLogging(false);
        // opt.EnableDetailedErrors(false);
        opt.EnableSensitiveDataLogging(false);
        var connectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");
        sqlType = sqlType.ToLower();
        // 根据工具变量传递的数据库类型处理。
        if (sqlType is "postgresql" or "pgsql")
        {
            connectionString ??= PgSqlConnectionString;
            // 解决pgsql的时间戳问题
            AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
            opt.UseNpgsql(connectionString).EnableSensitiveDataLogging(false);
        }
        else if (sqlType.IsNullOrWhiteSpace() || sqlType == "sqlite")
        {
            connectionString ??= SqlitePathConnectionString;
            opt.UseSqlite(connectionString).EnableSensitiveDataLogging(false);
        }

        if (connectionString.IsNullOrWhiteSpace()) throw new Exception("未配置数据库连接字符串！");
    })
    .AddEventBus(options =>
    {
        //配置和添加领域事件总线
        options.UseUoW<AutoDbContext>();
    })
    .AddCors(options => //配置和添加跨域资源共享 (CORS) 中间件
    {
        options.AddPolicy(corsPolicy, corsBuilder =>
        {
            corsBuilder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader()
                .AllowCredentials();
        });
    })
    // .AddIntegrationEventBus(option =>
    // {
    //     option.UseDapr()
    //         .UseEventLog<AutoDbContext>()
    //         .UseUoW<AutoDbContext>();
    // })
    .AddDomainEventBus(options =>
    {
        options.UseEventBus();
        //配置和添加领域事件总线
        options.UseUoW<AutoDbContext>()
            .UseRepository<AutoDbContext>();
    })
    .AddAutoInject()
    .AddTranslationServices()
    .AddHostedService<CacheBackgroundService>()
    .AddHostedService<TranslateBackgroundService>()
    .AddHostedService<AutoTranslationSubBackgroundService>()
    .AddHostedService<TranslationDataSynchBackgroundService>()
    .AddSubtitleExtractionServices(builder.Configuration)
    .AddServices(builder, option => option.MapHttpMethodsForUnmatched = new string[] { "Post" });

// 启用中间件
app.UseRequestLocalization(options =>
{
    var cultures = new[] { "zh-CN", "en-US" };
    options.AddSupportedCultures(cultures);
    options.AddSupportedUICultures(cultures);
    options.SetDefaultCulture(cultures[0]);
    // 当Http响应时，将 当前区域信息 设置到 Response Header：Content-Language 中
    options.ApplyCurrentCultureToResponseHeaders = true;
});

// 初始化日志辅助类
LoggingHelper.Initialize(app.Services.GetRequiredService<ILoggerFactory>());

if (app.Environment.IsDevelopment())
{
    // app.UseSwagger().UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v1/swagger.json", "AutomaticSubtitlesAPI"));

    app.UseSwagger(options => { options.RouteTemplate = "/openapi/{documentName}.json"; });
    // app.MapOpenApi();
    app.MapScalarApiReference(options =>
    {
        // Object initializer
        options
            .WithPreferredScheme("Bearer") // Security scheme name from the OpenAPI document
                                           // .WithHttpBearerAuthentication(bearer => { bearer.Token = "your-bearer-token"; })
            .WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient);
        options.Title = "AutomaticSubtitles API ©await";
    });
    // .RequireAuthorization();
}


#region MigrationDb

using var context = app.Services.CreateScope().ServiceProvider.GetService<AutoDbContext>();
{
    try
    {
        sqlType = sqlType?.ToLower();
        // 根据工具变量传递的数据库类型处理。
        if (sqlType is "postgresql" or "pgsql")
            // 执行sql
            await context.Database.ExecuteSqlRawAsync("CREATE EXTENSION hstore;");
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }

    context!.Database.EnsureCreated();
}

#endregion

// if (app.Environment.IsDevelopment()) app.UseSwagger().UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v1/swagger.json", "AutomaticSubtitles API"));
// 下载FFmpeg二进制文件
var directoryWithFFmpegAndFFprobe = $"{Common.GlobalPath}Core";
if (!File.Exists(directoryWithFFmpegAndFFprobe + "/version.json"))
{
    Log.Information("下载FFmpeg二进制文件 开始...");
    await FFmpegDownloader.GetLatestVersion(FFmpegVersion.Official, directoryWithFFmpegAndFFprobe);
    Log.Information("下载FFmpeg二进制文件 结束...");
}

// 尝试预加载Whisper.net库
try
{
    Log.Information("尝试预加载Whisper.net库...");

    // 设置DLL搜索路径
    var assemblyLocation = Assembly.GetExecutingAssembly().Location;
    var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);

    // 获取运行时信息
    string architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLower();
    string platform = string.Empty;

    // 记录当前运行环境
    Log.Information($"当前运行环境: {RuntimeInformation.OSDescription}, 架构: {architecture}");

    // 根据当前操作系统确定平台
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        platform = "win";
        // 设置Whisper库的搜索路径
        var runtimePath = Path.Combine(assemblyDirectory, "runtimes", $"{platform}-{architecture}", "native");
        if (Directory.Exists(runtimePath))
        {
            Log.Information($"Windows环境: 设置Whisper库搜索路径: {runtimePath}");
            // 添加DLL搜索目录 (仅Windows平台使用)
            NativeMethods.SetDllDirectory(runtimePath);

            // 检查DLL文件存在情况
            var dllFiles = Directory.GetFiles(runtimePath, "whisper.dll");
            foreach (var file in dllFiles)
            {
                try
                {
                    var fileInfo = new FileInfo(file);
                    Log.Information($"Windows环境: 找到库文件: {file}, 大小: {fileInfo.Length} 字节");
                }
                catch (Exception ex)
                {
                    Log.Warning($"Windows环境: 检查文件信息时出错: {ex.Message}");
                }
            }
        }
        else
        {
            Log.Warning($"Windows环境: 未找到Whisper.net库的运行时目录: {runtimePath}");
        }
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
    {
        platform = "linux";
        var runtimePath = Path.Combine(assemblyDirectory, "runtimes", $"{platform}-{architecture}", "native");
        Log.Information($"Linux环境: 检测运行时目录: {runtimePath}");

        if (Directory.Exists(runtimePath))
        {
            Log.Information($"Linux环境: 检测到Whisper.net库目录: {runtimePath}");

            // 记录库文件是否存在
            var libFiles = Directory.GetFiles(runtimePath, "libwhisper.*");
            if (libFiles.Length > 0)
            {
                foreach (var file in libFiles)
                {
                    try
                    {
                        var fileInfo = new FileInfo(file);
                        Log.Information($"Linux环境: 找到库文件: {file}, 大小: {fileInfo.Length} 字节, 权限: {fileInfo.Attributes}");
                    }
                    catch (Exception ex)
                    {
                        Log.Warning($"Linux环境: 检查文件信息时出错: {ex.Message}");
                    }
                }
            }
            else
            {
                Log.Warning($"Linux环境: 在目录 {runtimePath} 中未找到libwhisper.*文件");

                // 列出所有存在的文件
                var allFiles = Directory.GetFiles(runtimePath);
                if (allFiles.Length > 0)
                {
                    Log.Information($"Linux环境: 目录中存在 {allFiles.Length} 个文件:");
                    foreach (var file in allFiles)
                    {
                        Log.Information($"Linux环境: 文件: {Path.GetFileName(file)}");
                    }
                }
                else
                {
                    Log.Warning($"Linux环境: 目录 {runtimePath} 为空");
                }
            }

            // Linux环境下检查系统库目录
            if (File.Exists("/usr/lib/libwhisper.so") || File.Exists("/usr/lib/x86_64-linux-gnu/libwhisper.so"))
            {
                Log.Information("Linux环境: 在系统库目录中找到libwhisper.so");
            }

            // 检查环境变量
            Log.Information($"Linux环境: 当前LD_LIBRARY_PATH: {Environment.GetEnvironmentVariable("LD_LIBRARY_PATH")}");

            // 在Linux环境下提供常见故障排除建议
            Log.Information("Linux环境: 若遇到库加载问题，请尝试:");
            Log.Information("1. 安装必要的依赖: sudo apt-get install -y libgomp1");
            Log.Information("2. 确保libwhisper.so文件存在并有执行权限: chmod +x libwhisper.so");
            Log.Information("3. 设置环境变量: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/app/runtimes/linux-x64/native/");
        }
        else
        {
            Log.Warning($"Linux环境: 库目录不存在: {runtimePath}");

            // 检查上级目录结构
            var runtimesDir = Path.Combine(assemblyDirectory, "runtimes");
            if (Directory.Exists(runtimesDir))
            {
                var subDirs = Directory.GetDirectories(runtimesDir);
                Log.Information($"Linux环境: runtimes目录包含以下子目录: {string.Join(", ", subDirs.Select(Path.GetFileName))}");
            }
            else
            {
                Log.Warning($"Linux环境: runtimes目录不存在: {runtimesDir}");
            }
        }
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
    {
        platform = "osx";
        Log.Information($"MacOS环境: Whisper.net库路径可能为: runtimes/{platform}-{architecture}/native");
    }

    Log.Information($"当前运行平台: {platform}-{architecture}, OS描述: {RuntimeInformation.OSDescription}");

    // 确保模型目录存在
    var modelDir = Path.Combine(Common.GlobalPath, "WhisperModels");
    Directory.CreateDirectory(modelDir);
}
catch (Exception ex)
{
    Log.Warning(ex, "预加载Whisper.net库时出错，这可能会影响字幕提取功能");
}

// TesseractHelper.TessDataPath = $"{Common.GlobalPath}/TessData";
// await TesseractHelper.DownloadAllTessDataAsync();
FFmpeg.SetExecutablesPath(directoryWithFFmpegAndFFprobe);

app.UseStaticFiles();
app.UseResponseCompression();
app.UseAuthentication(); // 启用身份验证
app.UseAuthorization();
app.UseCors(corsPolicy); // 启用授权、启用 CORS 中间件，并指定策略名称
// app.UseRouting();
// app.Use(async (context, next) =>
// {
//     if (context.Request.Path == "/") context.Request.Path = "/index.html";
//     await next();
//     if (context.Response.StatusCode == 404)
//     {
//         context.Request.Path = "/index.html";
//         await next();
//     }
// });

app.UseMasaExceptionHandler();
app.UseMiddleware<ExceptionMiddleware>();

// 初始化依赖解析器
AutomaticSubtitles.Service.Infrastructure.Helper.DependencyResolver.Initialize(app.Services);

// app.Services.GetService<ChatMessageHandle>();
Log.Information("AutomaticSubtitles Service is running...");
await app.RunAsync();
Log.CloseAndFlush();

// 在文件最后添加P/Invoke定义
public static partial class NativeMethods
{
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool SetDllDirectory(string lpPathName);
}